#include "hardware.h"
#include <Arduino.h>

static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 20];
TFT_eSPI tft(240, 240);

uint8_t* BufWithDma = (uint8_t *)heap_caps_malloc(DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  if ( y >= tft.height()) return false;
  tft.pushImageDMA(x, y, w, h, bitmap, (uint16_t *)BufWithDma);
  return true;
}

void my_disp_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
{
	uint32_t w = (area->x2 - area->x1 + 1);
	uint32_t h = (area->y2 - area->y1 + 1);

	tft.startWrite();
	tft.setAddrWindow(area->x1, area->y1, w, h);
	tft.pushColors(&color_p->full, w * h, true);
	tft.endWrite();
	// tft.pushImage(area->x1, area->y1, w, h, (uint16_t *)color_p);
	lv_disp_flush_ready(disp);
}

Hardware::Hardware()
{
	init_display();
	lv_fs_if_init();
}
void Hardware::init_hardware()
{
	save_cfg.begin("Config");
	reset();
	event_ini();
    init_sdcard();
	auto_task();

	imu = new IMU;
	rgb = new Pixel;
    light_sen = new Ambient(ONE_TIME_L_RESOLUTION_MODE);
	rgb->setRGB(255, 255, 255);
    rgb->setBrightness(0); 
	init_rgb_gradual_change();
}

void Hardware::init_display()
{
	ledcSetup(LCD_BL_PWM_CHANNEL, 5000, 8);
	ledcAttachPin(LCD_BL_PIN, LCD_BL_PWM_CHANNEL);

	lv_init();

	// lv_log_register_print_cb(my_print); /* register print function for debugging */
	set_back_light(0);
	tft.begin(); /* TFT init */
	tft.fillScreen(TFT_BLACK);
	tft.setRotation(4); /* mirror 修改反转，如果加上分光棱镜需要改为4镜像*/
	tft.initDMA();
	lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 20);

	/*Initialize the display*/
	lv_disp_drv_t disp_drv;
	lv_disp_drv_init(&disp_drv);
	disp_drv.hor_res = 240;
	disp_drv.ver_res = 240;
	disp_drv.flush_cb = my_disp_flush;
	disp_drv.buffer = &disp_buf;
	lv_disp_drv_register(&disp_drv);

	TJpgDec.setJpgScale(1);
	TJpgDec.setSwapBytes(1);
	TJpgDec.setCallback(tft_output);
}

void Hardware::set_back_light(float duty)
{
	duty = constrain(duty, 0, 1);
	duty = 1 - duty;
	ledcWrite(LCD_BL_PWM_CHANNEL, (int)(duty * 255));
}

void Hardware::init_sdcard()
{
    SPIClass* sd_spi = new SPIClass(HSPI); // another SPI
    if (!SD.begin(15, *sd_spi, 40000000)) // SD-Card SS pin is 15
    {
      Serial.println("Card Mount Failed");
      return;
    }
    uint8_t cardType = SD.cardType();

    if (cardType == CARD_NONE)
    {
      Serial.println("No SD card attached");
      return;
    }
    Serial.println("SD loaded successfully!");
}

Action Hardware::get_action(int time)
{
    return imu->update(time);
}

void Hardware::main_process(Event event)
{
	event_run(event);
	// if (millis()-timer_lux>10000)
	// {
	// 	dis_lux();
	// 	timer_lux = millis();
	// }
}

void Hardware::dis_lux()
{
	lux = light_sen->getLux();
	aux = 0.2 + 3 * lux/255;
	set_back_light(aux);
}

void Hardware::reset()
{
	String msg;
	msg = save_cfg.getString("lum", "60");
	set_back_light(msg.toFloat()/100.0);

	msg = save_cfg.getString("power", "high");
	if (msg=="low")
		setCpuFrequencyMhz(80);
	else if(msg=="medium")
		setCpuFrequencyMhz(160);
	else
		setCpuFrequencyMhz(240);
}